from eim.tools.dbtool import DBTool
from eim.tools.searchtool import MatchLogic,PartnerRS,SearchCondition,SearchConditionList
from eim.DataBasModals.mode import t_powers,t_operate,t_rs_roleoperate,t_role
from eim.result.page_result import PageResult
from eim.result.simple_result import SimpleResult
from flask import current_app
from sqlalchemy import func,select,update,delete,text,or_,and_,insert,join
from sqlalchemy.engine import LegacyRow,Connection,CursorResult
import copy

class PowerService:
    """
    系统功能服务
    """
    def __init__(self,condb):
        """
        系统功能服务的构造函数
        """
        self.db=condb
        
    def getPowerByCode(self,powercode:str)->dict:
        """
        通过功能编码获取功能信息

        Args:
            powercode (str): 功能编码

        Returns:
            dict: 功能信息
        """
        try:
            con = self.db.engine.connect()
            qry=select(t_powers).where(t_powers.c.pcode==powercode).limit(1).offset(0)
            res:CursorResult = con.execute(qry)
            row:LegacyRow = res.first()
            if row==None:
                raise Exception("指定编码的功能条目不存在")
            return row._asdict()
        except Exception as es:
            raise es
    
    def _upgradeParentSystem(self,con:Connection,pid:int):
        """
        刷新指定id的系统条目状态

        Args:
            con (Connection): 已经开启了事务的数据库连接
            pid (int): 待更新的系统条目id
        """
        try:
            qry=select(t_powers).where(t_powers.c.ID==pid)
            res:CursorResult = con.execute(qry)
            row:LegacyRow = res.first()
            powercode = row["pcode"]
            qry=select(func.count(t_powers.c.ID)).where(t_powers.c.pcode==powercode)
            res=con.execute(qry)
            cnt = res.scalar()
            vals={}
            if cnt<=0:
                vals={
                    "powertype":"01"
                }
            else:
                vals={
                    "powertype":"00"
                }
            qry=update(t_powers).values(vals).where(t_powers.c.ID==pid)
            con.execute(qry)
        except Exception as es:
            raise es
        
    
    def append(self,pname:str,powertype:str,parent:str,powerowner:str,URL:str)->int:
        """
        添加新的功能记录

        Args:
            pname (str): 功能名称
            powertype (str): 功能类别
            parent (str): 父功能
            powerowner (str): 功能所属 
            URL (str): 资源定位地址

        Returns:
            int: 返回新的功能记录id
        """
        powercode:str = None
        from eim.tools.dbtool import DBTool
        dt:DBTool = DBTool(self.db)
        powercode = dt.getNewCode("power","PW","",6)
        con:Connection = self.db.engine.connect()
        tran = con.begin()
        try: 
            if(pname==""):
                raise Exception("功能名称不能为空")
            if(powertype not in ('00','01')):
                raise Exception("功能类别的取值不正确")
            if(powerowner not in ('00','01')):
                raise Exception("系统功能所属的取值不正确")
            
            vals={}
            # 指定了父级功能
            if parent!="": 
                pp = self.getPowerByCode(parent)
                if(pp==None):
                    raise Exception("指定的父功能不存在")
                if(pp["powertype"]=="01"):
                    raise Exception("指定的父及功能为叶子功能，不能单做父级功能使用")
                strlv = pp["level"]
                lv = 0 if strlv=="" else int(strlv)
                lv +=1
                vals = {
                    "pcode":powercode,
                    "pname": pname,
                    "powertype": powertype,
                    "parent": parent,
                    "powerowner": powerowner,
                    "level":lv,
                    "URL":URL
                }
                pid = pp["ID"]
                # 更新父级状态
                self._upgradeParentSystem(con,pid)
            # 没有父级功能
            else:
                vals = {
                    "pcode":powercode,
                    "pname": pname,
                    "powertype": powertype,
                    "parent": parent,
                    "powerowner": powerowner,
                    "level":0,
                    "URL":URL
                }
                
            
            qry = insert(t_powers).values(vals)
            res:CursorResult = con.execute(qry)
            rc = res.inserted_primary_key[0]
            tran.commit()
            return rc
        except Exception as es:
            tran.rollback()
            dt.returnCode('power','',powercode)
            raise es
    
    def appendPowerOperate(self,pcode:str,oname:str)->int:
        """
        根据功能编号为指定的系统功能操作

        Args:
            pcode (str): 指定功能的功能编号
            oname(str): 操作中文名称
        Returns:
            int: 添加功能的完成状态
        """
        try:
            from eim.tools.dbtool import DBTool
            tool = DBTool(self.db)
            precode = f"{pcode}_"
            optcode = tool.getNewCode(pcode,precode)
            pms={
                "ocode":optcode,
                "powercode":pcode,
                "oname":oname
            }
            con:Connection = self.db.engine.connect()
            qry=insert(t_operate).values(pms)
            res:CursorResult=con.execute(qry)
            return res.rowcount
        except Exception as es:
            raise es
        
    def upgrade(self,id:int,upvals:dict)->int:
        """
        更新选中ID的系统功能条目

        Args:
            id (int): 待删除的系统ID
            upvals (dict): 更新条目的属性字典

        Raises:
            es: 更新过程产生的异常

        Returns:
            int: 返回受影响行数
        """
        con:Connection = self.db.engine.connect()
        tran = con.begin()
        try:
            if "parent" in upvals.keys():
                parent = upvals["parent"]
                if(parent==""):
                    upvals["level"]=0
                else:
                    pp = self.getPowerByCode(parent)
                    lv = int(pp['level'])+1
                    upvals["level"]=lv
                    pid = pp["ID"]
                    # 更新父级状态
                    self._upgradeParentSystem(con,pid)
            qry = update(t_powers).values(upvals)
            qry = qry.where(t_powers.c.ID==id)
            res:CursorResult = con.execute(qry)
            rc = res.rowcount
            tran.commit()
            return rc
        except Exception as es:
            tran.rollback()
            raise es
        
    def deletePowerByID(self,id:int)->int:
        """
        删除指定ID的系统功能条目

        Args:
            id (int): 待删除的系统功能条目ID

        Returns:
            int: 返回受影响行数
        """
        try:
            con = self.db.engine.connect()
            # 获取待删除的系统功能条目
            curpower=None
            qry=select(t_powers).where(t_powers.c.ID==id).limit(1).offset(0)
            curpower=con.execute(qry).first()
            if(curpower==None):
                raise Exception("待删除的系统功能条目不存在")
            curpower = curpower._asdict()
            if(curpower["powerowner"]=="00"):
                raise Exception("系统功能所属类别不能删除")
            # 判定是否存在子功能项，如果存在不能删除
            pcode = curpower["pcode"]
            qry = select(func.count(t_powers.c.ID)).where(t_powers.c.parent==pcode)
            res:CursorResult = con.execute(qry)
            cnt = res.scalar()
            if(cnt>0):
                raise Exception("该系统条目存在子条目不能删除")
            
            # 判定是否存在系统功能的操作清单，如果存在不能删除
            qry = select(func.count(t_operate.c.ID)).where(t_operate.c.powercode==pcode)
            res:CursorResult = con.execute(qry)
            cnt = res.scalar()
            if(cnt>0):
                raise Exception("功能操作表中尚存在该系统功能的功能条目，不能对该系统功能条目进行删除操作")
            
            # 根据ID删除系统功能条目
            qry = delete(t_powers).where(t_powers.c.ID==id)
            res:CursorResult = con.execute(qry)
            return res.rowcount
        except Exception as es:
            raise es
    
    def getPowerTree(self,con:Connection,parentNode:dict=None):
        """
        系统功能菜单树

        Args:
            parentNode (dict): 父级节点
        """
        try:
            keys = parentNode.keys()
            if("ID" not in keys):
                parentNode["ID"]=""
            if("pcode" not in keys):
                parentNode["pcode"]=""
            if("pname" not in keys):
                parentNode["pname"]="root"
            if("powertype" not in keys):
                parentNode["powertype"]="00"
            if("parent" not in keys):
                parentNode["parent"]=""
            if("powerowner" not in keys):
                parentNode["powerowner"]="00"
            if("level" not in keys):
                parentNode["level"]="-1"
            if("URL" not in keys):
                parentNode["URL"]=""
            if("children" not in keys):
                parentNode["children"]=[]
            pcode = parentNode["pcode"]
            
            qry = select(t_powers).where(t_powers.c.parent==pcode).order_by(t_powers.c.ID,func.length(t_powers.c.pname))
            res:CursorResult = con.execute(qry)
            for row in res.fetchall():
                parentNode["children"].append(row._asdict())
            
            for node in parentNode["children"]:
                self.getPowerTree(con,node)
            
            return parentNode
        except Exception as es:
            raise es

    def getPowerTreeByRole(self,ptree:dict,auops:dict)->dict:
        """
        通过角色编码获取系统功能树

        Args:
            ptree (dict): 所有功能树
            auops (dict): 所有角色授权
        Returns:
            dict: 系统功能树
        """
        
        def findOptsByCode(authorizes,pcode)->dict:
            # 根据功能编号从授权数组中获取操作数组
            res=None
            powerauth = authorizes["powerauth"]
            for n in powerauth:
                if n["pcode"]==pcode:
                    res=n["opts"]
                    break
            return res
        
        def getOptStatus(opts)->bool:
            # 判定操作数组中是否存在可执行权限的操作
            res=False
            for o in opts:
                f = o["authorize"]
                if(f):
                    res = True
                    break
                else:
                    pass
            return res
        
            
        try:            
            if (len(ptree["children"])<=0) and (ptree["powertype"]==00):
                # 没有子功能且功能类型是非叶子节点可用状态置为否定
                ptree["enable"]= False
            elif(len(ptree["children"])>0) and (ptree["powertype"]=="00"):
                # 存在子节点且非叶子节点循环子节点递归进入
                ptree["enable"]= False
                for node in ptree["children"]:
                    ct=self.getPowerTreeByRole(node,auops)
                    if ct["enable"]:
                        ptree["enable"]= True
            else:
                # 不存在子节点且为叶子节点根据操作状态更新可用状态并添加操作数据
                pcode = ptree["pcode"]
                opts = findOptsByCode(auops,pcode)
                if(opts==None):
                    ptree["enable"] = False
                else:
                    ptree["children"]=opts
                    ptree["enable"] = getOptStatus(opts)
            
            return ptree                                
        except Exception as es:
            raise es
    
    def getLeafPower(self)->list:
        """
        获取叶子功能
        """
        try:
            rs=[]
            con:Connection = self.db.engine.connect()
            qry=select(t_powers.c.pcode,t_powers.c.pname)
            qry=qry.where(t_powers.c.powertype=='01')
            res:CursorResult = con.execute(qry)
            for row in res.fetchall():
                rd = row._asdict()
                rd["opts"]=[]
                rs.append(rd)
            return rs
        except Exception as es:
            raise es
    
    def getRoleOptionsDict(self)->dict:
        """
        获取角色操作授权信息的字典结构,key值为角色code与option编码的组合两个编码用|分割,value值是授权内容
        Returns:
            dict: 角色授权列表
        """
        try:
            con:Connection = self.db.engine.connect()
            qry = select(t_rs_roleoperate)
            res:CursorResult = con.execute(qry)
            result={}
            for row in res.fetchall():
                rcode = row["rcode"]
                ocode = row["ocode"]
                authorize = row["authorize"]
                k=f"{rcode}|{ocode}"
                result[k]=authorize
            return result
        except Exception as es:
            raise es
    

    def getAllRoleAuthStatus(self):
        """
        获取指定角色的操作状态
        """
        try:
            #获取系统功能操作结构数组
            powerOpts=self.getPowerOptions()
            #获取现有的角色功能配置字典结构,其中key值为rcode+|+ocode,value值为授权状态
            authDict = self.getRoleOptionsDict()
            #获取authDict的keys
            authkeys = authDict.keys()
            
            # 最终结果数组result
            result=[]

            #组织每个角色的功能授权列表
            con:Connection = self.db.engine.connect()
            qry=select(t_role.c.rcode,t_role.c.rname)
            res:CursorResult = con.execute(qry)
            roleAuthorize = []
            for row in res.fetchall():
                rc = row["rcode"]
                pr = copy.deepcopy(powerOpts)
                item={
                    "rcode": rc,
                    "powerauth": pr
                }
                result.append(item)
            
            #组织每个角色功能的更新标记
            for role in result:
                for power in role["powerauth"]:
                    for opt in power["opts"]:
                        oc = opt["ocode"]
                        rc = role["rcode"]
                        k = f"{rc}|{oc}"
                        if(k in authkeys):
                            opt["editflag"]="update"
                            flg = authDict[k]
                            if flg=="01":
                                opt["authorize"]=False
                            else:
                                opt["authorize"]=True
                        else:
                            opt["editflag"]="insert"
                            
            return result               
        except Exception as es:
            raise es
    
    def getRoleOptionsAuthStatus(self,rcode:str)->dict:
        """
        通过角色编号和角色名称获取角色的功能操作授权

        Args:
            rcode (str): 角色编号

        Returns:
            dict: 角色授权列表
        """
        try:
            #获取系统功能操作结构数组
            powerOpts=self.getPowerOptions()
            #获取现有的角色功能配置字典结构,其中key值为rcode+|+ocode,value值为授权状态
            authDict = self.getRoleOptionsDict()
            #获取authDict的keys
            authkeys = authDict.keys()
            
            # 最终结果数组result
            result={}
            
            roleAuthorize = []
          
            result["rcode"]=rcode
            result["powerauth"]=copy.deepcopy(powerOpts)
            
            #组织每个角色功能的更新标记
            role=result
            for power in role["powerauth"]:
                for opt in power["opts"]:
                    oc = opt["ocode"]
                    rc = role["rcode"]
                    k = f"{rc}|{oc}"
                    if(k in authkeys):
                        opt["editflag"]="update"
                        flg = authDict[k]
                        if flg=="01":
                            opt["authorize"]=False
                        else:
                            opt["authorize"]=True
                    else:
                        opt["editflag"]="insert"
                            
            return result               
        except Exception as es:
            raise es
    
    
    def getPowerOptions(self)->list:
        """
        先获取叶子功能,再获取叶子功能的操作

        Returns:
            list: 获取叶子功能的操作,并添加写入状态辅助字段,用于角色授权时决定写入数据库时的方法
        """
        try:
            leaf:list=[]
            leaf=self.getLeafPower()
            con:Connection = self.db.engine.connect()
            qry=select(t_operate.c.ocode,t_operate.c.oname,t_operate.c.powercode)
            for node in leaf:
                pcode = node["pcode"]
                qry1=qry.where(t_operate.c.powercode==pcode)
                cursor:CursorResult = con.execute(qry1)
                for row in cursor.fetchall():
                    opt=row._asdict()
                    opt["authorize"]=False
                    node["opts"].append(opt)
                
            return leaf
        except Exception as es:
            raise es
        
    def upgradeRoleAuthorize(self,rcode:str,ocode:str,authorize:bool)->int:
        """
        根据指定的角色编码与指定的操作编码更新授权状态

        Args:
            rcode (str): 角色编码
            ocode (str): 操作编码
            authorize (bool): 授权状态

        Returns:
            int: 受影响的行数
        """
        try:
            auth= "00" if authorize else "01"
            
            con:Connection = self.db.engine.connect()
            param={
                "authorize":auth
            }
            qry = update(t_rs_roleoperate).values(param)
            qry=qry.where(and_(t_rs_roleoperate.c.rcode==rcode,t_rs_roleoperate.c.ocode==ocode))
            res:CursorResult = con.execute(qry)
            return res.rowcount
        except Exception as es:
            raise es
    
    def insertRoleAuthorize(self,rcode:str,ocode:str,authorize:bool)->int:
        """
        根据角色编号及操作编号新增授权

        Args:
            rcode (str): 角色编号
            ocode (str): 操作编号
            authorize (bool): 授权

        Returns:
            int: 受影响行数
        """
        try:
            auth= "00" if authorize else "01"
            
            con:Connection = self.db.engine.connect()
            param={
                "rcode":rcode,
                "ocode":ocode,
                "authorize":auth
            }
            qry = insert(t_rs_roleoperate).values(param)
            res:CursorResult = con.execute(qry)
            return res.rowcount
        except Exception as es:
            raise es
    